
#ifndef UM_SINGLETON_H
#define UM_SINGLETON_H

#include <memory>

namespace UM {


class DefaultSingletonLocker {
};

struct DefaultSingletonError {
	static void throwException(HRESULT) {
		DebugBreak();
	}
};

template <
	class T,
	class _Locker = DefaultSingletonLocker,
	class _ErrorPolicy = DefaultSingletonError
>
class SingletonHolder : public T {

public:

	static T& instance() {
		
		if (element.get() == 0) {
			makeInstance();
		}

		return *(element.get());

	}

private:

	SingletonHolder() {
	}

	static void makeInstance() {

		_Locker locker;
		(locker);

		if (element.get() == 0) {
			T * obj;
			HRESULT hr = T::NewL(&obj);
			if (FAILED(hr)) {
				_ErrorPolicy::throwException(hr);
			}
			element.reset(obj);
		}

	}

	static std::auto_ptr<T> element;

};

template <class T>
std::auto_ptr<T> _init_element(std::auto_ptr<T> e) {
	return e.get() == 0 ? e : std::auto_ptr<T>(e.release());
};

template <class T, class _Locker, class _ErrorPolicy>
__declspec(selectany) std::auto_ptr<T> SingletonHolder<T, _Locker, _ErrorPolicy>::element = _init_element(SingletonHolder<T, _Locker, _ErrorPolicy>::element);

} // namespace UM

using UM::SingletonHolder;


#endif // UM_SINGLETON_H